#include <iostream>
#include <list>

enum TokenType
{
	TokenType_Integer,
	TokenType_Real,
	TokenType_Name,
	TokenType_String,
	TokenType_ArrayBegin,
	TokenType_ArrayEnd,
	TokenType_DictionaryBegin,
	Tokentype_DictionaryEnd,

	Keyword_R,				// R
	Keyword_Null,			// null
	Keyword_True,			// true
	Keyword_False,			// false
	Keyword_Obj,			// obj
	Keyword_EndObj,			// endobj
	Keyword_Stream,			// stream
	Keyword_EndStream,		// endstream
	Keyword_XRef,			// xref
	Keyword_StartXRef,		// startxref
	Keyword_Trailer,		// trailer
	Keyword_SaveGS,			// q
	Keyword_RestoreGS,		// Q
	Keyword_ModifyCTM,		// cm
	Keyword_LineWidth,		// w
	Keyword_LineCap,		// J
	Keyword_LineJoin,		// j
	Keyword_MiterLimit,		// M
	Keyword_LineDash,		// d
	Keyword_ColorIntent,	// ri
	Keyword_Flatness,		// i
	Keyword_SetGS,			// gs
	// TODO: other content stream commands
};

enum ObjectType
{
	ObjectType_Null,
	ObjectType_Boolean,
	ObjectType_Integer,
	ObjectType_Real,
	ObjectType_Name,
	ObjectType_String,
	ObjectType_Array,
	ObjectType_Dictionary,
	ObjectType_Indirect,
};

struct Reference
{
	unsigned int identifier;
	unsigned int generation;
};

struct Variant
{
	ObjectType type;
	union
	{
		bool	  valueBoolean;
		int		  valueInteger;
		double	  valueReal;
		size_t    valueName;
		Reference valueIndirect;
		size_t	  length;
	};

	Variant() : type(ObjectType_Null)
	{
	}

	Variant(ObjectType type) : type(type)
	{
	}

	Variant(bool value) 
		: type(ObjectType_Boolean)
		, valueBoolean(value)
	{
	}

	Variant(int value) 
		: type(ObjectType_Integer)
		, valueInteger(value)
	{
	}

	Variant(double value)
		: type(ObjectType_Real)
		, valueReal(value)
	{
	}

	Variant(int identifier, int generation) 
		: type(ObjectType_Indirect)
	{
		valueIndirect.identifier = identifier;
		valueIndirect.generation = generation;
	}
};

struct Boolean
{
};

struct Integer
{
};

struct Real
{
};

struct Name
{
};

struct String
{
};

struct Array
{
};

struct Dictionary
{
};

struct Parser
{
	std::list<Variant>  pool;
	std::list<Variant*> stack;

	virtual void onToken(TokenType tokenType) = 0;
};

struct DocumentParser : public Parser
{
	void onObj(Integer const &identifier, Integer const &generation);
	void onXRef();
	void onStartXRef();
	void onTrailer();
};

struct ObjectParser : public Parser
{
	void onNull();
	void onTrue();
	void onFalse();
	void onInteger();
	void onReal();
	void onName();
	void onString();
	void onArrayBegin();
	void onArrayEnd();
	void onDictionaryBegin();
	void onDictionaryEnd();

	virtual void handleToken(TokenType tokenType)
	{
		switch (tokenType)
		{
		case TokenType_Integer:
			return onInteger();
		case TokenType_Real:
			return onReal();
		case TokenType_Name:
			return onName();
		case TokenType_String:
			return onString();
		case TokenType_ArrayBegin:
			return onArrayBegin();
		case TokenType_ArrayEnd:
			return onArrayEnd();
		case TokenType_DictionaryBegin:
			return onDictionaryBegin();
		case Tokentype_DictionaryEnd:
			return onDictionaryEnd();
		case Keyword_Null:
			return onNull();
		case Keyword_True:
			return onTrue();
		case Keyword_False:
			return onFalse();
		}
	}
};

struct IndirectObjectParser : public ObjectParser
{
	void onStream(const Dictionary &stream);
	void onEndObj();
};

struct StreamParser
{
	void onEndStream();
};

struct ContentStreamParser : public ObjectParser
{
	void onSaveGS();
	void onRestoreGS();
	void onModifyCTM(Real const &a, Real const &b, Real const &c, Real const &d, Real const &e, Real const &f);
	void onLineWidth(Real const &width);
	void onLineCap(Integer const &cap);
	void onLineJoin(Integer const &join);
	void onMiterLimit(Real const &limit);
	void onDashPattern(Array const &pattern, Integer const &phase);
	void onColorIntent(Name const &intent);
	void onFlatness(Integer const &flatness);
	void onSetGS(Name const &extgs);
	// TODO: other content stream commands
};

int main()
{

}